import cv2 as cv
import numpy as np
from skimage import morphology
import scipy.spatial as spt
import math
import serial
import re


# *坐标捕捉类


class Pointcapture():
    # *本类的主要功能是捕捉屏幕上的红色激光光斑、
    # * 绿色激光光斑以及黑色胶布矩形框的中心线点，并规划路线
    zero_point = (0, 0)   # 参考坐标原点
    # 参数
    # 可视区域参数
    fov_x0 = 15
    fov_y0 = 120
    fov_x1 = 450
    fov_y1 = 560

    # 红色光斑识别参数
    red_hsv_hlow = 30
    red_hsv_hhigh = 32
    red_hsv_slow = 0
    red_hsv_shigh = 10
    red_hsv_vlow = 230
    red_hsv_vhigh = 255
    # 绿色光斑识别参数
    green_hsv_hlow = 30
    green_hsv_hhigh = 32
    green_hsv_slow = 0
    green_hsv_shigh = 10
    green_hsv_vlow = 230
    green_hsv_vhigh = 255
    # 黑框路线识别参数
    contour_index = 1
    contour_ignore = 10
    contour_outlength = 7
    contour_Filterforce = 11
    contour_binaryval = 100

    def __init__(self):  # 初始化类的属性
        pass

    def setZeroPoint(self, zpt):
        """设置参考零点位置

        Args:
            zpt (tuple): 新的坐标原点
        """
        self.zero_point = zpt

    def addtext(self, img, text, pos, color, ):
        """用于在图像上添加临时观测的文本

        Args:
            img (_type_): 要添加文本的图像载体
            text (_type_): 要添加的文本字符串
            pos (_type_): 要添加文本的位置坐标
            color (_type_): 文本颜色
            zero_point (tuple, optional): 要添加的文本的位置坐标的参考原点. Defaults to (0, 0).
        """
        font = cv.FONT_HERSHEY_SIMPLEX
        try:
            pos = (pos[0] + self.zero_point[0], pos[1] + self.zero_point[1])
        except TypeError:
            pos = (0, 0)
        cv.putText(img, text, pos, font, 1, color, 2, cv.LINE_AA)

    def __enlargeContour(self, points, length):
        if len(points) <= 1:
            return [], None
        M = cv.moments(points)
        try:
            centralpoint = (int(M['m10']/M['m00']), int(M['m01']/M['m00']))
        except ZeroDivisionError:
            return [], None

        res_list = []
        for i in range(len(points)):
            try:
                th = math.atan(
                    abs(points[i][0][1]-centralpoint[1])/abs(points[i][0][0]-centralpoint[0]))
            except ZeroDivisionError:
                if points[i][1]-centralpoint[1] > 0:
                    th = math.Pi/2
                else:
                    th = math.Pi/2

            if points[i][0][1]-centralpoint[1] < 0 and points[i][0][0]-centralpoint[0] > 0:
                delta_x = (length+0.5)*math.cos(th)
                delta_y = -(length+0.5)*math.sin(th)
            elif points[i][0][1]-centralpoint[1] > 0 and points[i][0][0]-centralpoint[0] >= 0:
                delta_x = (length+0.5)*math.cos(th)
                delta_y = (length+0.5)*math.sin(th)
            elif points[i][0][1]-centralpoint[1] >= 0 and points[i][0][0]-centralpoint[0] < 0:
                delta_x = -(length+0.5)*math.cos(th)
                delta_y = (length+0.5)*math.sin(th)
            elif points[i][0][1]-centralpoint[1] < 0 and points[i][0][0]-centralpoint[0] < 0:
                delta_x = -(length+0.5)*math.cos(th)
                delta_y = -(length+0.5)*math.sin(th)
            else:
                delta_x = (length+0.5)*math.cos(th)
                delta_y = -(length+0.5)*math.sin(th)
            res_list.append(
                (int(points[i][0][0]+delta_x), int(points[i][0][1]+0.5+delta_y)))
        return res_list, centralpoint

    def __endpoints_of_skeleton(self, center_line_img):
        """计算骨线图上的端点位置

        Args:
            center_line_img (skeleton_img): 要计算的骨线图

        Returns:
            list: 包含所有端点坐标元组的列表
        """
        W, H = center_line_img.shape
        img = center_line_img
        endpoints = []
        x, y = np.where(img > 0)

        for i, j in zip(x, y):
            if i - 1 < 0 or j - 1 < 0 or i + 1 >= W or j + 1 >= H:
                continue
                # 条件A 该点的四领域内仅有一个点与之连接
            c_a = (img[i - 1, j] + img[i + 1, j] +
                   img[i, j - 1] + img[i, j + 1]) == 255

            # 条件B 该点的对角领域内仅有一个点与之连接
            c_b = (img[i - 1, j - 1] + img[i - 1, j + 1] +
                   img[i + 1, j - 1] + img[i + 1, j + 1]) == 255

            # 该点的八领域内仅有一个点
            if (img[i - 1:i + 2, j - 1:j + 2] == 255).sum() <= 2:
                endpoints.append([i, j])

            # 同时满足两个条件AB，且设置八种其余的端点坐标情况，如：
            '''
            ##0  0##         
            0#0  0#0   ...
            000  000
            '''
            if c_a and c_b:
                if (img[i - 1, j - 1:j + 2] == 255).sum() == 2 or (img[i + 1, j - 1:j + 2] == 255).sum() == 2 or \
                        (img[i - 1:i + 2, j - 1] == 255).sum() == 2 or (img[i - 1:i + 2, j + 1] == 255).sum() == 2:
                    endpoints.append([i, j])
        return endpoints

    def getReddotPos(self, img, display=True):
        """获取红色光斑的坐标

        Args:
            img (wild_img): 摄像头数据或原生图片
        Returns:
            position(point): 返回红点坐标
            result_img(mark_img):标注后的图像
        """
        img = img.copy()
        kernel = np.ones((5, 5), np.uint8)
        img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
        # 定义HSV中掩码通过色彩的范围
        lower_val = np.array(
            [self.red_hsv_hlow, self.red_hsv_slow, self.red_hsv_vlow])
        upper_val = np.array(
            [self.red_hsv_hhigh, self.red_hsv_shigh, self.red_hsv_vhigh])
        # 设置HSV的阈值,得到掩码图
        mask = cv.inRange(img_hsv, lower_val, upper_val)
        # 膨胀
        dilation = cv.dilate(mask, kernel, iterations=1)
        # # 侵蚀
        erosion = cv.erode(dilation, kernel, iterations=1)
        # 二值化
        _, thresh = cv.threshold(erosion, 100, 255, 0)
        # # 得到轮廓坐标
        thresh, contours, hierarchy = cv.findContours(
            thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
        # 得到质心坐标
        # 默认质心坐标设置
        position = (None, None)
        result_img = None
        areas = []
        # 获取有效质心坐标
        for each in contours:
            areas.append(cv.contourArea(each))
        try:
            index = areas.index(max(areas))
        except ValueError:
            return position, img
        try:
            cnt = contours[index]
            M = cv.moments(cnt)
            try:
                position = (int(M['m10'] / M['m00']) - self.zero_point[0],
                            int(M['m01'] / M['m00'] - self.zero_point[1]))
            except ZeroDivisionError:
                pass
        except IndexError:
            pass
        # 绘制所用轮廓
        if display:
            result_img = cv.drawContours(img, contours, -1, (158, 168, 3), 3)
        return position, result_img

    # 绿色激光捕捉函数
    def getGreendotPos(self, img, hl, hh, sl, sh, vl, vh, display=False):
        """获取绿色光斑的坐标

        Args:
            img (wild_img): 摄像头数据或原生图片
            hl (int): 色调低阈值
            hh (int): 色调高阈值
            sl (int): 饱和度低阈值
            sh (int): 饱和度高阈值
            vl (int): 亮度低阈值
            vh (int): 亮度高阈值

        Returns:
            position(point): 返回红点坐标
            result_img(mark_img):标注后的图像
        """
        img = img.copy()
        kernel = np.ones((5, 5), np.uint8)
        img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
        # 定义HSV中掩码通过色彩的范围
        lower_val = np.array([hl, sl, vl])
        upper_val = np.array([hh, sh, vh])
        # 设置HSV的阈值,得到掩码图
        mask = cv.inRange(img_hsv, lower_val, upper_val)
        # 膨胀
        dilation = cv.dilate(mask, kernel, iterations=1)
        # # 侵蚀
        erosion = cv.erode(dilation, kernel, iterations=1)
        # 二值化
        _, thresh = cv.threshold(erosion, 100, 255, 0)
        # # 得到轮廓坐标
        thresh, contours, hierarchy = cv.findContours(
            thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
        # 得到质心坐标
        # 默认质心坐标设置
        position = (None, None)
        areas = []
        # 获取有效质心坐标
        for each in contours:
            areas.append(cv.contourArea(each))
        try:
            index = areas.index(max(areas))
        except ValueError:
            return position, img
        try:
            cnt = contours[0]
            M = cv.moments(cnt)
            try:
                position = (int(M['m10'] / M['m00']) - self.zero_point[0],
                            int(M['m01'] / M['m00'] - self.zero_point[1]))
            except ZeroDivisionError:
                pass
        except IndexError:
            pass
        # 绘制所用轮廓
        if display:
            result_img = cv.drawContours(img, contours, -1, (158, 168, 3), 3)
            return position, result_img
        else:
            return position

    def getBlackRoute(self, img, optimize=False):
        """获取黑色胶布布置的路线中心线,并返回循迹排序坐标点

        Args:
            img (wild_img): 原生图像（要求背景干净）
            optimize (bool, optional): 是否开启路线优化. Defaults to False.

        Returns:
            route_list, skeleton:路线有序列表(绝对坐标)，骨线图
        """
        img = img.copy()
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        # 高斯模糊滤波
        blur = cv.GaussianBlur(img_gray, (11, 11), 0)
        # 阈值得到黑色框
        _, binary = cv.threshold(blur, 100, 255, cv.THRESH_BINARY_INV)
        # 二值化
        binary[binary == 255] = 1
        # 细化算法,寻找黑框骨线
        skeleton0 = morphology.skeletonize(binary)
        skeleton = skeleton0.astype(np.uint8) * 255
        # 去除分叉点
        while optimize:
            endpoints = self.__endpoints_of_skeleton(skeleton)
            if len(endpoints) == 0:
                break
            for each in endpoints:
                skeleton[each[0], each[1]] = 0
        # 获取骨架线上的所有坐标
        indices = np.argwhere(skeleton)
        points = [tuple(index[::-1]) for index in indices]
        route_list = []
        tree = spt.cKDTree(data=points)
        route_list.append(points[0])
        del points[0]
        distances, indexs = tree.query(route_list[0], k=3)
        route_list.append(points[min(indexs[1:]) - 1])
        del points[min(indexs[1:] - 1)]
        length = len(points)
        for i in range(length):
            tree = spt.cKDTree(data=points)
            distances, indexs = tree.query(route_list[-1], k=1)
            route_list.append(points[indexs])
            del points[indexs]
            if len(points) == 1:
                route_list.append(points[0])
                break
        return route_list, skeleton

    def getContourSum(self, img):
        img = img.copy()
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        # 高斯模糊滤波
        blur = cv.GaussianBlur(
            img_gray, (self.contour_Filterforce, self.contour_Filterforce), 0)
        # 阈值得到黑色框
        _, binary = cv.threshold(
            blur, self.contour_binaryval, 255, cv.THRESH_BINARY_INV)
        _, contours, _ = cv.findContours(
            binary, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
        return len(contours)

    def getBlackRectRoute(self, img):
        img = img.copy()
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        # 高斯模糊滤波
        blur = cv.GaussianBlur(
            img_gray, (self.contour_Filterforce, self.contour_Filterforce), 0)
        # 阈值得到黑色框
        _, binary = cv.threshold(
            blur, self.contour_binaryval, 255, cv.THRESH_BINARY_INV)
        _, contours, hierarchy = cv.findContours(
            binary, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
        cnt = []
        # for each in contours:
        #     print(cv.contourArea(each))
        #     if cv.contourArea(each)<=41240+500 and cv.contourArea(each)>=41240-500 :
        #         cnt = each
        if len(contours) <= self.contour_index:
            return (None, None), [], []
        cnt = contours[self.contour_index]
        if len(cnt) == 0:
            return (None, None), [], []
        points = []
        res_list = []
        orgin_list = []
        points, center = self.__enlargeContour(cnt, self.contour_outlength)
        if len(points) == 0:
            return (None, None), [], []
        if self.contour_ignore <= 1:
            self.contour_ignore = 1
        for i in range(len(points)):
            if i % self.contour_ignore == 0:
                res_list.append(points[i])
                orgin_list.append(cnt[i])
        return center, res_list, orgin_list


class Peripheral():
    # * 外设类，本类主要功能是实现和单片机之间的uart通信，以及PWM控制步进电机的实现
    Uart = None

    def uartInit(self, baud):
        self.Uart = serial.Serial("/dev/ttyAMA0", baud)

    def getUartData(self, wait=False):
        while wait:
            count = self.Uart.inWaiting()
            if count != 0:
                break
        if wait == False:
            count = self.Uart.inWaiting()
            if count == 0:
                return None
        data = self.Uart.read(count).decode('utf-8')
        self.Uart.flushInput()
        return data

    def sendUartData(self, data):
        return self.Uart.write(f"{data}".encode('utf-8'))


class WorkModel():
    model = 0             # 模式判别量
    debug = False
    oldmodel = -1         # 模式记忆量

    def nothing():
        pass

    def redCapture(self, peri, pointcap, cap):
        # red point debug window
        _, frame = cap.read()
        redpos, reddrawimg = pointcap.getReddotPos(frame, True)
        if self.debug:
            cv.putText(reddrawimg, str(redpos), (100, 100),
                        cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv.LINE_AA)
            cv.imshow('redcapdebug', reddrawimg)
            cv.waitKey(1) & 0xFF
        if redpos != (None, None):
            peri.sendUartData(f"STRRC%{redpos[0]}*{redpos[1]}#RS")
        else:
            peri.sendUartData("STRERRS")  # 没有捕获到红色光斑,返回错误代码（数据标识）：ER


    def blackRouteCapture(self, peri, pointcap, cap):
        # 设定数据包的头尾
        sendbuf = "ST"+"R"+"BR"+"%"
        endbuf = "-1*0*0"+"#"+"RS"
        _, frame = cap.read()
        frame = frame[pointcap.fov_x0:pointcap.fov_x1,
                        pointcap.fov_y0:pointcap.fov_y1]
        _, route_list, __ = pointcap.getBlackRectRoute(frame)
        index = 0
        if len(route_list) == 0:
            peri.sendUartData("STRERRS")  # 没有捕获到黑色边框,返回错误代码（数据标识）：ER
        else:
            for each in route_list:
                sendbuf += f"{index}*{each[0]}*{each[1]}*"
                index += 1
                if self.debug:
                    cv.circle(frame, tuple(each), 1, (0, 0, 255), -1)
                    cv.imshow('route', frame)
                    cv.waitKey(1) & 0xFF
            sendbuf += endbuf
            peri.sendUartData(sendbuf)

    def setFov(self,pointcap, cap):
        basedata = {'upside': pointcap.fov_x0,
                    'downside': pointcap.fov_x1,
                    'leftside': pointcap.fov_y0,
                    'rightside': pointcap.fov_y1}
        adjustwindowname = 'FOV adjust window'
        resultwindowname = 'FOV result window'
        cv.namedWindow(adjustwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        cv.namedWindow(resultwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        tipimg = cv.imread(
            "/home/pi/eagain-base/RaspiCode/source/windowstip.png")
        cv.imshow(adjustwindowname, tipimg)
        cv.resizeWindow(adjustwindowname, 900, 700)
        cv.resizeWindow(resultwindowname, 700, 700)
        cv.moveWindow(adjustwindowname, 710, 35)
        cv.moveWindow(resultwindowname, 0, 35)
        cv.createTrackbar('upside', adjustwindowname,
                            pointcap.fov_x0, 479, self.nothing)
        cv.createTrackbar('downside', adjustwindowname,
                            pointcap.fov_x1, 479, self.nothing)
        cv.createTrackbar('leftside', adjustwindowname,
                            pointcap.fov_y0, 639, self.nothing)
        cv.createTrackbar('rightside', adjustwindowname,
                            pointcap.fov_y1, 639, self.nothing)
        cv.createTrackbar('cancel', adjustwindowname, 0, 1, self.nothing)
        cv.createTrackbar('save', adjustwindowname, 0, 1, self.nothing)
        while True:
            # 效果显示
            cv.resizeWindow(adjustwindowname, 900, 700)
            cv.resizeWindow(resultwindowname, 700, 700)
            cv.moveWindow(adjustwindowname, 710, 35)
            cv.moveWindow(resultwindowname, 0, 35)
            _, frame = cap.read()
            frame = frame[pointcap.fov_x0:pointcap.fov_x1,
                            pointcap.fov_y0:pointcap.fov_y1]
            try:
                cv.imshow(resultwindowname, frame)
            except cv.error:
                errorimg1 = cv.imread(
                    "/home/pi/eagain-base/RaspiCode/source/windowserror.png")
                cv.imshow(resultwindowname, errorimg1)
            k = cv.waitKey(5) & 0xFF
            # 参数设置
            pointcap.fov_x0 = cv.getTrackbarPos(
                'upside', adjustwindowname)
            pointcap.fov_x1 = cv.getTrackbarPos(
                'downside', adjustwindowname)
            pointcap.fov_y0 = cv.getTrackbarPos(
                'leftside', adjustwindowname)
            pointcap.fov_y1 = cv.getTrackbarPos(
                'rightside', adjustwindowname)
            if cv.getTrackbarPos('save', adjustwindowname):
                cv.destroyAllWindows()
                pointcap.model = 0
                break
            elif cv.getTrackbarPos('cancel', adjustwindowname):
                pointcap.fov_x0 = basedata['upside']
                pointcap.fov_x1 = basedata['downside']
                pointcap.fov_y0 = basedata['leftside']
                pointcap.fov_y1 = basedata['rightside']
                cv.destroyAllWindows()
                pointcap.model = 0
                break

    def setRedCaptureParam(self,pointcap,cap):
        basedata = {'hl': pointcap.red_hsv_hlow,
                        'hh': pointcap.red_hsv_hhigh,
                        'sl': pointcap.red_hsv_slow,
                        'sh': pointcap.red_hsv_shigh,
                        'vl': pointcap.red_hsv_vlow,
                        'vh': pointcap.red_hsv_vhigh}
        adjustwindowname = 'RedPoint adjust window'
        resultwindowname = 'RedPoint result window'
        cv.namedWindow(adjustwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        cv.namedWindow(resultwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        tipimg = cv.imread("/home/pi/eagain-base/RaspiCode/source/redtip.png")
        cv.imshow(adjustwindowname, tipimg)
        cv.resizeWindow(adjustwindowname, 900, 700)
        cv.resizeWindow(resultwindowname, 700, 700)
        cv.moveWindow(adjustwindowname, 710, 35)
        cv.moveWindow(resultwindowname, 0, 35)
        cv.createTrackbar('hl', adjustwindowname,
                            pointcap.red_hsv_hlow, 180, self.nothing)
        cv.createTrackbar('hh', adjustwindowname,
                            pointcap.red_hsv_hhigh, 180, self.nothing)
        cv.createTrackbar('sl', adjustwindowname,
                            pointcap.red_hsv_slow, 255, self.nothing)
        cv.createTrackbar('sh', adjustwindowname,
                            pointcap.red_hsv_shigh, 255, self.nothing)
        cv.createTrackbar('vl', adjustwindowname,
                            pointcap.red_hsv_vlow, 255, self.nothing)
        cv.createTrackbar('vh', adjustwindowname,
                            pointcap.red_hsv_vhigh, 255, self.nothing)
        cv.createTrackbar('cancel', adjustwindowname, 0, 1, self.nothing)
        cv.createTrackbar('save', adjustwindowname, 0, 1, self.nothing)
        while True:
            # 识别效果显示
            cv.resizeWindow(adjustwindowname, 900, 700)
            cv.resizeWindow(resultwindowname, 700, 700)
            cv.moveWindow(adjustwindowname, 710, 35)
            cv.moveWindow(resultwindowname, 0, 35)
            _, frame = cap.read()
            frame = frame[pointcap.fov_x0:pointcap.fov_x1,
                            pointcap.fov_y0:pointcap.fov_y1]
            redpos, reddrawimg = pointcap.getReddotPos(
                frame, display=True)
            cv.putText(reddrawimg, str(redpos), (100, 100),
                        cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv.LINE_AA)
            cv.imshow(resultwindowname, reddrawimg)
            k = cv.waitKey(5) & 0xFF
            # 参数设置
            pointcap.red_hsv_hlow = cv.getTrackbarPos(
                'hl', adjustwindowname)
            pointcap.red_hsv_hhigh = cv.getTrackbarPos(
                'hh', adjustwindowname)
            pointcap.red_hsv_slow = cv.getTrackbarPos(
                'sl', adjustwindowname)
            pointcap.red_hsv_shigh = cv.getTrackbarPos(
                'sh', adjustwindowname)
            pointcap.red_hsv_vlow = cv.getTrackbarPos(
                'vl', adjustwindowname)
            pointcap.red_hsv_vhigh = cv.getTrackbarPos(
                'vh', adjustwindowname)
            if cv.getTrackbarPos('save', adjustwindowname):
                cv.destroyAllWindows()
                pointcap.model = 0
                break
            elif cv.getTrackbarPos('cancel', adjustwindowname):
                pointcap.red_hsv_hlow = basedata['hl']
                pointcap.red_hsv_hhigh = basedata['hh']
                pointcap.red_hsv_slow = basedata['sl']
                pointcap.red_hsv_shigh = basedata['sh']
                pointcap.red_hsv_vlow = basedata['vl']
                pointcap.red_hsv_vhigh = basedata['vh']
                cv.destroyAllWindows()
                pointcap.model = 0
                break
            
    def setBlackRouteParam(self,pointcap,cap):
        basedata = {"index": pointcap.contour_index,
                        'ignore': pointcap.contour_ignore,
                        'outlength': pointcap.contour_outlength}
        adjustwindowname = 'BlackRect adjust window'
        resultwindowname = 'BlackRect result window'
        cv.namedWindow(adjustwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        cv.namedWindow(resultwindowname, cv.WINDOW_NORMAL)  # 创建调试窗口
        tipimg = cv.imread(
            "/home/pi/eagain-base/RaspiCode/source/blacktip.png")
        cv.imshow(adjustwindowname, tipimg)
        cv.resizeWindow(adjustwindowname, 900, 700)
        cv.resizeWindow(resultwindowname, 700, 700)
        cv.moveWindow(adjustwindowname, 710, 35)
        cv.moveWindow(resultwindowname, 0, 35)
        _, frame = cap.read()
        frame = frame[pointcap.fov_x0:pointcap.fov_x1,
                        pointcap.fov_y0:pointcap.fov_y1]
        cv.createTrackbar('index', adjustwindowname, pointcap.contour_index,
                            pointcap.getContourSum(frame)-1, self.nothing)
        cv.createTrackbar('ignore', adjustwindowname,
                            pointcap.contour_ignore, 40, self.nothing)
        cv.createTrackbar('outlength', adjustwindowname,
                            pointcap.contour_outlength, 30, self.nothing)
        cv.createTrackbar('cancel', adjustwindowname, 0, 1, self.nothing)
        cv.createTrackbar('save', adjustwindowname, 0, 1, self.nothing)
        while True:
            # 识别效果显示
            cv.resizeWindow(adjustwindowname, 900, 700)
            cv.resizeWindow(resultwindowname, 700, 700)
            cv.moveWindow(adjustwindowname, 710, 35)
            cv.moveWindow(resultwindowname, 0, 35)
            _, frame = cap.read()
            frame = frame[pointcap.fov_x0:pointcap.fov_x1,
                            pointcap.fov_y0:pointcap.fov_y1]
            try:
                _, route_list, rect_center = pointcap.getBlackRectRoute(
                    frame)
            except Exception:
                route_list = []
            if len(route_list) == 0:
                cv.imshow(resultwindowname, frame)
            else:
                for each in route_list:
                    cv.circle(frame, tuple(each), 1, (0, 0, 255), -1)
                    cv.imshow(resultwindowname, frame)
                    k = cv.waitKey(5) & 0xFF
            # 参数设置
            pointcap.contour_index = cv.getTrackbarPos(
                'index', adjustwindowname)
            pointcap.contour_ignore = cv.getTrackbarPos(
                'ignore', adjustwindowname)
            pointcap.contour_outlength = cv.getTrackbarPos(
                'outlength', adjustwindowname)
            if cv.getTrackbarPos('save', adjustwindowname):
                cv.destroyAllWindows()
                pointcap.model = 0
                break
            elif cv.getTrackbarPos('cancel', adjustwindowname):
                pointcap.contour_index = basedata['index']
                pointcap.contour_ignore = basedata['ignore']
                pointcap.contour_outlength = basedata['outlength']
                cv.destroyAllWindows()
                pointcap.model = 0
                break